package com.quectel.cms.controller.parkingcard;


import cn.hutool.core.lang.func.LambdaUtil;
import com.google.common.base.Preconditions;
import com.quectel.business.common.parking.ParkingGateCmdBusiness;
import com.quectel.business.common.util.sys.SysCodeUtils;
import com.quectel.business.pay.PayBusiness;
import com.quectel.cms.controller.BaseController;
import com.quectel.cms.interceptor.LoginUserSession;
import com.quectel.cms.util.SessionHolder;
import com.quectel.cms.vo.parkingcard.AuditOrderReq;
import com.quectel.cms.vo.parkingcard.SignUpReq;
import com.quectel.constant.core.parking.CarParkingSpaceConstants;
import com.quectel.constant.core.parkingcard.ParkingCardMemberConstants;
import com.quectel.constant.core.parkingcard.ParkingCardOrderConstants;
import com.quectel.constant.global.SystemConstants;
import com.quectel.constant.global.annotation.RequirePermissions;
import com.quectel.constant.sys.SysCodeKeyConstants;
import com.quectel.core.module.car.dto.CarDto;
import com.quectel.core.module.car.service.CarService;
import com.quectel.core.module.carparking.dto.CarParkingSpaceDto;
import com.quectel.core.module.carparking.service.CarParkingSpaceService;
import com.quectel.core.module.device.service.DeviceService;
import com.quectel.core.module.device.service.DeviceTypeService;
import com.quectel.core.module.household.dto.HouseholdDto;
import com.quectel.core.module.household.service.HouseholdService;
import com.quectel.core.module.mobileuser.dto.MobileUserCarDto;
import com.quectel.core.module.mobileuser.service.MobileUserCarService;
import com.quectel.core.module.parkingcard.dto.ParkingCardDto;
import com.quectel.core.module.parkingcard.dto.ParkingCardMemberDto;
import com.quectel.core.module.parkingcard.dto.ParkingCardOrderDto;
import com.quectel.core.module.parkingcard.service.ParkingCardMemberService;
import com.quectel.core.module.parkingcard.service.ParkingCardOrderDeviceService;
import com.quectel.core.module.parkingcard.service.ParkingCardOrderService;
import com.quectel.core.module.parkingcard.service.ParkingCardService;
import com.quectel.pay.module.order.constants.OrderRefundConstants;
import com.quectel.pay.module.order.service.PayOrderService;
import com.quectel.util.common.*;
import com.quectel.util.kit.PageFetchKit;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
 * @author ryan
 * @email ryan.ran@quectel.com
 * @date 2023/04/18 17:23
 */
@RestController
@RequestMapping("parkingCardOrder")
@Tag(name = "ParkingCardOrderController", description = "停车卡办理订单相关api")
public class ParkingCardOrderController extends BaseController {

    @DubboReference
    private ParkingCardOrderService parkingCardOrderService;
    @DubboReference
    private PayOrderService payOrderService;
    @DubboReference
    private ParkingCardService parkingCardService;
    @DubboReference
    private ParkingCardMemberService parkingCardMemberService;
    @DubboReference
    private CarService carService;
    @DubboReference
    private MobileUserCarService mobileUserCarService;
    @DubboReference
    private HouseholdService householdService;
    @DubboReference
    private CarParkingSpaceService carParkingSpaceService;
    @DubboReference
    private DeviceService deviceService;
    @DubboReference
    private DeviceTypeService deviceTypeService;
    @DubboReference
    private ParkingCardOrderDeviceService parkingCardOrderDeviceService;
    @Autowired
    private PayBusiness payBusiness;
    @Autowired
    private ParkingGateCmdBusiness parkingGateCmdBusiness;

    /**
     * 购卡记录导出
     */
    @GetMapping("/exportPurchaseExcel")
    @RequirePermissions(values = "parkingCardOrder:exportExcel")
    @Operation(summary = "购卡记录导出")
    public void exportPurchaseExcel(@RequestParam Map<String, Object> params, HttpServletResponse hresp) {
        Request request = Request.configParamsNotPage(params);
        request.put(LambdaUtil.getFieldName(ParkingCardOrderDto::getAuditStatus), ParkingCardOrderConstants.OrderAuditStatusEnum.AUDITED.getAuditStatus());

        super.fillAuthorityData(params);

        List<ParkingCardOrderDto> result = PageFetchKit.fetchAll(r -> parkingCardOrderService.queryList(r), request.getParams());
        String[] headers = new String[]{"所属小区", "来源", "订单编号", "车牌号码", "车牌颜色", "车主姓名", "车主手机", "月卡名称", "月卡类型", "车位名称", "支付方式", "支付状态", "实收金额", "开票状态", "备注", "办理日期", "审核日期"};
        List<String[]> dataList = new ArrayList<>();
        for (ParkingCardOrderDto data : result) {
            String[] item = new String[headers.length];
            item[0] = Objects.nonNull(data.getVillage()) ? data.getVillage().getName() : SystemConstants.EMPTY_STR;
            item[1] = SysCodeUtils.easyToGetName(SysCodeKeyConstants.ParkingCardSourceType, data.getSourceType() + "");
            item[2] = data.getOrderNo();
            item[3] = data.getLicense();
            item[4] = SysCodeUtils.easyToGetName(SysCodeKeyConstants.LICENSE_COLOR, data.getLicenseColor() + "");
            item[5] = Objects.nonNull(data.getCar()) ? data.getCar().getOwnerName() : "";
            item[6] = Objects.nonNull(data.getCar()) ? data.getCar().getOwnerMobile() : "";
            item[7] = Objects.nonNull(data.getParkingCard()) ? data.getParkingCard().getName() : "";
            item[8] = SysCodeUtils.easyToGetName(SysCodeKeyConstants.PARKING_CARD_TYPE, data.getCardType() + "");
            item[9] = Objects.nonNull(data.getCarParkingSpace()) ? data.getCarParkingSpace().getName() : "";
            item[10] = SysCodeUtils.easyToGetName(SysCodeKeyConstants.PARKING_CARD_PAY_TYPE, data.getPayType() + "");
            item[11] = SysCodeUtils.easyToGetName(SysCodeKeyConstants.PARKING_CARD_PAY_STATUS, data.getPayStatus() + "");
            item[12] = data.getPayAmount().subtract(data.getRefundAmount()).toPlainString();
            item[13] = SysCodeUtils.easyToGetName(SysCodeKeyConstants.INVOICE_STATUS, data.getInvoiceStatus() + "");
            item[14] = data.getRemark();
            item[15] = Objects.nonNull(data.getTransactTime()) ? DateUtils.format(data.getTransactTime(), DateUtils.FormatType.COMMON) : "";
            item[16] = Objects.nonNull(data.getAuditTime()) ? DateUtils.format(data.getAuditTime(), DateUtils.FormatType.COMMON) : "";
            dataList.add(item);
        }
        POIUtils.exportExcel(hresp, "购卡记录", headers, dataList, "购卡记录");

    }

    /**
     * 购卡记录
     * 已审核的购卡记录(不包含驳回直接退款记录，包含已审核再退款的记录)
     *
     * @param pageNo
     * @param pageSize
     * @return
     */
    @GetMapping("purchaseList")
    @RequirePermissions(values = "parkingCardOrder:list")
    @Operation(summary = "购卡记录")
    public Response<Page<ParkingCardOrderDto>> purchaseList(
            @Parameter(description = "从1开始的页码数") @RequestParam Integer pageNo,
            @Parameter(description = "每页多少条") @RequestParam Integer pageSize
    ) {
        //查询列表数据
        Request request = Request.configParams(Request.parseParams(httpServletRequest));
        request.put(LambdaUtil.getFieldName(ParkingCardOrderDto::getAuditStatus), ParkingCardOrderConstants.OrderAuditStatusEnum.AUDITED.getAuditStatus());

        super.fillAuthorityData(request.getParams());
        int total = parkingCardOrderService.queryTotal(request.getParams());

        List<ParkingCardOrderDto> list = null;
        if (total > 0) {
            list = parkingCardOrderService.queryList(request.getParams());
        } else {
            list = new ArrayList<>();
        }

        for (ParkingCardOrderDto parkingCardOrderDto : list) {
            if (ParkingCardOrderConstants.OrderPayStatusEnum.IS_REFUND.getPayStatus().equals(parkingCardOrderDto.getPayStatus())) {
                parkingCardOrderDto.setReceiptsAmount(parkingCardOrderDto.getPayAmount().subtract(parkingCardOrderDto.getRefundAmount()));
            }
        }

        Page<ParkingCardOrderDto> page = new Page<>(request.getPageNo(), request.getPageSize(), total, list);
        return Response.<Page<ParkingCardOrderDto>>ok().wrap(page);
    }

    /**
     * 包月记录导出
     */
    @GetMapping("/exportExcel")
    @RequirePermissions(values = "parkingCardOrder:exportExcel")
    @Operation(summary = "包月记录导出")
    public void exportExcel(@RequestParam Map<String, Object> params, HttpServletResponse hresp) {
        Request request = Request.configParamsNotPage(params);

        super.fillAuthorityData(params);

        List<ParkingCardOrderDto> result = PageFetchKit.fetchAll(r -> parkingCardOrderService.queryList(r), request.getParams());
        String[] headers = new String[]{"所属小区", "来源", "订单编号", "车牌号码", "车牌颜色", "车主姓名", "车主手机", "审核状态", "月卡名称", "月卡类型", "车位名称", "实付金额", "支付方式", "支付状态", "退款金额", "退款日期", "开票状态", "备注", "办理日期", "审核日期"};
        List<String[]> dataList = new ArrayList<>();
        for (ParkingCardOrderDto data : result) {
            String[] item = new String[headers.length];
            item[0] = Objects.nonNull(data.getVillage()) ? data.getVillage().getName() : SystemConstants.EMPTY_STR;
            item[1] = SysCodeUtils.easyToGetName(SysCodeKeyConstants.ParkingCardSourceType, data.getSourceType() + "");
            item[2] = data.getOrderNo();
            item[3] = data.getLicense();
            item[4] = SysCodeUtils.easyToGetName(SysCodeKeyConstants.LICENSE_COLOR, data.getLicenseColor() + "");
            item[5] = Objects.nonNull(data.getCar()) ? data.getCar().getOwnerName() : "";
            item[6] = Objects.nonNull(data.getCar()) ? data.getCar().getOwnerMobile() : "";
            item[7] = SysCodeUtils.easyToGetName(SysCodeKeyConstants.ParkingCardAuditStatus, data.getAuditStatus() + "");
            item[8] = Objects.nonNull(data.getParkingCard()) ? data.getParkingCard().getName() : "";
            item[9] = SysCodeUtils.easyToGetName(SysCodeKeyConstants.PARKING_CARD_TYPE, data.getCardType() + "");
            item[10] = Objects.nonNull(data.getCarParkingSpace()) ? data.getCarParkingSpace().getName() : "";
            item[11] = data.getPayAmount().toPlainString();
            item[12] = SysCodeUtils.easyToGetName(SysCodeKeyConstants.PARKING_CARD_PAY_TYPE, data.getPayType() + "");
            item[13] = SysCodeUtils.easyToGetName(SysCodeKeyConstants.PARKING_CARD_PAY_STATUS, data.getPayStatus() + "");
            item[14] = data.getRefundAmount().toPlainString();
            item[15] = Objects.nonNull(data.getRefundTime()) ? DateUtils.format(data.getRefundTime(), DateUtils.FormatType.COMMON) : "";
            item[16] = SysCodeUtils.easyToGetName(SysCodeKeyConstants.INVOICE_STATUS, data.getInvoiceStatus() + "");
            ;
            item[17] = data.getRemark();
            item[18] = Objects.nonNull(data.getTransactTime()) ? DateUtils.format(data.getTransactTime(), DateUtils.FormatType.COMMON) : "";
            item[19] = Objects.nonNull(data.getAuditTime()) ? DateUtils.format(data.getAuditTime(), DateUtils.FormatType.COMMON) : "";
            dataList.add(item);
        }
        POIUtils.exportExcel(hresp, "包月记录", headers, dataList, "包月记录");

    }

    /**
     * 分页查询
     *
     * @param pageNo
     * @param pageSize
     * @return
     */
    @GetMapping("list")
    @RequirePermissions(values = "parkingCardOrder:list")
    @Operation(summary = "分页列表")
    public Response<Page<ParkingCardOrderDto>> list(
            @Parameter(description = "从1开始的页码数") @RequestParam Integer pageNo,
            @Parameter(description = "每页多少条") @RequestParam Integer pageSize
    ) {
        //查询列表数据
        Request request = Request.configParams(Request.parseParams(httpServletRequest));

        super.fillAuthorityData(request.getParams());
        int total = parkingCardOrderService.queryTotal(request.getParams());

        List<ParkingCardOrderDto> list = null;
        if (total > 0) {
            list = parkingCardOrderService.queryList(request.getParams());
        } else {
            list = new ArrayList<>();
        }

        Page<ParkingCardOrderDto> page = new Page<>(request.getPageNo(), request.getPageSize(), total, list);
        return Response.<Page<ParkingCardOrderDto>>ok().wrap(page);
    }

    /**
     * 编辑查询反显
     *
     * @param id
     * @return
     */
    @GetMapping("infoForEdit/{id}")
    @RequirePermissions(values = "parkingCardOrder:edit")
    @Operation(summary = "查询单条记录")
    public Response<ParkingCardOrderDto> infoForEdit(@PathVariable("id") Long id) {

        Map<String, Object> params = new HashMap<>();
        super.fillAuthorityData(params);
        params.put(SystemConstants.ENTITY_ID_FLAG, String.valueOf(id));
        if (parkingCardOrderService.queryTotal(params) <= 0) {
            return Response.error(SystemConstants.ILLEGAL_MSG);
        }

        ParkingCardOrderDto parkingCardOrderDto = parkingCardOrderService.selectById(id);

        return Response.<ParkingCardOrderDto>ok().wrap(parkingCardOrderDto);
    }

    /**
     * 详情
     *
     * @param id
     * @return
     */
    @GetMapping("info/{id}")
    @RequirePermissions(values = "parkingCardOrder:info")
    @Operation(summary = "查询单条记录")
    public Response<ParkingCardOrderDto> info(@PathVariable("id") Long id) {

        Map<String, Object> params = new HashMap<>();
        super.fillAuthorityData(params);
        params.put(SystemConstants.ENTITY_ID_FLAG, String.valueOf(id));
        if (parkingCardOrderService.queryTotal(params) <= 0) {
            return Response.error(SystemConstants.ILLEGAL_MSG);
        }

        ParkingCardOrderDto parkingCardOrderDto = parkingCardOrderService.selectById(id);

        return Response.<ParkingCardOrderDto>ok().wrap(parkingCardOrderDto);
    }

    /**
     * 办理
     *
     * @param signUpReq
     * @return
     */
    @PostMapping("signUp")
    @RequirePermissions(values = "parkingCardOrder:edit")
    @Operation(summary = "办理")
    public Response<Object> signUp(@RequestBody @Validated SignUpReq signUpReq) {

        ParkingCardDto parkingCardDto = parkingCardService.selectCacheById(signUpReq.getCardId());
        if (Objects.isNull(parkingCardDto)) {
            return Response.error("月卡配置不存在");
        }

        CarParkingSpaceDto carParkingSpaceDto = carParkingSpaceService.selectCacheById(signUpReq.getCarParkingSpaceId());
        if (Objects.isNull(carParkingSpaceDto)) {
            return Response.error("车位不存在");
        }
        if (CarParkingSpaceConstants.SpaceStateEnum.SOLD.getState().equals(carParkingSpaceDto.getState())) {
            return Response.error("已售车位不允许分配");
        }

        ParkingCardMemberDto parkingCardMemberDto = parkingCardMemberService.selectOneMember(parkingCardDto.getVillageId()
                , signUpReq.getLicense(), signUpReq.getLicenseColor());
        if (Objects.nonNull(parkingCardMemberDto)
                && ParkingCardMemberConstants.MemberIsFreezeEnum.IS_FREEZE.getFreezeStatus().equals(parkingCardMemberDto.getIsFreeze())) {
            return Response.error("会员被冻结");
        }

        HouseholdDto householdDto = householdService.selectByVillageIdAndMobile(parkingCardDto.getVillageId(), signUpReq.getOwnerMobile());
        if (Objects.isNull(householdDto)) {
            return Response.error("住户未认证");
        }

        Boolean isRegistCar = Boolean.TRUE;
        CarDto carDto = carService.selectOneByCache(parkingCardDto.getVillageId()
                , signUpReq.getLicense(), signUpReq.getLicenseColor());
        if (Objects.isNull(carDto)) {
            // 用户车辆未认证，找到移动端用户车辆，提交认证
            isRegistCar = Boolean.FALSE;

            List<MobileUserCarDto> mobileUserCarDtoList = mobileUserCarService.selectByMobile(signUpReq.getOwnerMobile());
            MobileUserCarDto mobileUserCarDto = mobileUserCarDtoList.parallelStream().filter(o -> o.getLicense().equals(signUpReq.getLicense())
                    && o.getLicenseColor().equals(signUpReq.getLicenseColor())).findFirst().orElse(null);
            if (Objects.nonNull(mobileUserCarDto)) {
                carDto = CopyUtils.copyObj(mobileUserCarDto, CarDto.class);
            } else {
                // cms办理会员，车辆信息可能为不存在的 (在注册车辆里和mobileUser车辆里都没有)
                carDto = new CarDto();
                carDto.setLicense(signUpReq.getLicense());
                carDto.setLicenseColor(signUpReq.getLicenseColor());
                carDto.setEngineNo(signUpReq.getEngineNo());
                carDto.setVehicleIdNo(signUpReq.getVehicleIdNo());
                carDto.setFrontViewPictures(signUpReq.getFrontViewPictures());
                carDto.setVehicleLicensePictures(signUpReq.getVehicleLicensePictures());
                carDto.setBrandModel(signUpReq.getBrandModel());
            }
            carDto.setTenantId(householdDto.getTenantId());
            carDto.setVillageId(householdDto.getVillageId());
            carDto.setCarType(signUpReq.getCarType());
            carDto.setOwnerName(householdDto.getName());
            carDto.setOwnerMobile(householdDto.getMobile());
            super.fillSaveCommonData(carDto);
        } else {
            // 认证车辆不为空，查看是否为当前住户的车辆
            if (!carDto.getOwnerMobile().equals(householdDto.getMobile())) {
                return Response.error("该车辆已被其他人认证，请确认车牌信息");
            }
        }

        final Date currentDate = new Date();

        ParkingCardOrderDto orderReq = new ParkingCardOrderDto();
        orderReq.setTenantId(parkingCardDto.getTenantId());
        orderReq.setVillageId(parkingCardDto.getVillageId());
        orderReq.setSourceType(ParkingCardOrderConstants.OrderSourceTypeEnum.ADMIN.getSourceType());
        orderReq.setSourceId(SessionHolder.getSysUserId());
        orderReq.setIsRegistCar(Boolean.TRUE.equals(isRegistCar) ? ParkingCardOrderConstants.OrderIsRegistCarEnum.IS_REGIST.getRegistStatus()
                : ParkingCardOrderConstants.OrderIsRegistCarEnum.NO_REGIST.getRegistStatus());
        orderReq.setCarId(carDto.getId());
        orderReq.setHouseholdId(householdDto.getId());
        orderReq.setLicense(carDto.getLicense());
        orderReq.setLicenseColor(carDto.getLicenseColor());
        orderReq.setAuditStatus(ParkingCardOrderConstants.OrderAuditStatusEnum.NO_AUDIT.getAuditStatus());
        orderReq.setCarParkingSpaceId(carParkingSpaceDto.getId());
        orderReq.setCardId(parkingCardDto.getId());
        orderReq.setCardType(parkingCardDto.getType());
        orderReq.setCardJson(JacksonUtils.toJsonString(parkingCardDto));
        orderReq.setPayType(ParkingCardOrderConstants.OrderPayTypeEnum.OFFLINE.getPayType());
        orderReq.setPayStatus(ParkingCardOrderConstants.OrderPayStatusEnum.PAY_SUCCESS.getPayStatus());
        orderReq.setPayAmount(signUpReq.getPayAmount());
        orderReq.setInvoiceStatus(ParkingCardOrderConstants.OrderInvoiceStatusEnum.NO_INVOICE.getInvoiceStatus());
        orderReq.setTransactTime(currentDate);
        orderReq.setAuditTime(currentDate);
        orderReq.setPaymentVoucher(signUpReq.getPaymentVoucher());
        Long save = parkingCardOrderService.save(orderReq);
        if (save != null) {
            // 这里的车辆只能set进去，因为来源于cms录入，可能系统任何地方都没有该车辆信息，cms录入后审核通过直接成为认证车辆
            orderReq.setCar(carDto);
            orderReq.setId(save);
            // 审核
            Date deadline = parkingCardOrderService.approve(orderReq);

            // 授权设备
            if (Objects.nonNull(deadline)) {
                parkingGateCmdBusiness.authorize(orderReq.getVillageId(), orderReq.getLicense(), orderReq.getLicenseColor(), deadline, save);
                return Response.ok();
            }
        }
        return Response.error("办理异常");
    }

    /**
     * 审核或关闭
     *
     * @param auditOrderReq
     * @return
     */
    @PostMapping("audit")
    @RequirePermissions(values = "parkingCardOrder:edit")
    @Operation(summary = "审核或关闭")
    public Response<Object> audit(@RequestBody @Validated AuditOrderReq auditOrderReq) {
        ParkingCardOrderDto parkingCardOrderDto = parkingCardOrderService.selectCacheById(auditOrderReq.getOrderId());
        if (Objects.isNull(parkingCardOrderDto)) {
            return Response.error("购卡订单不存在");
        }

        if (auditOrderReq.getStatus().equals(ParkingCardOrderConstants.AUDIT_TYPE)) {
            // 通过
            CarParkingSpaceDto carParkingSpaceDto = carParkingSpaceService.selectCacheById(auditOrderReq.getCarParkingSpaceId());
            if (Objects.isNull(carParkingSpaceDto)) {
                return Response.error("车位不存在");
            }
            if (CarParkingSpaceConstants.SpaceStateEnum.SOLD.getState().equals(carParkingSpaceDto.getState())) {
                return Response.error("已售车位不允许分配");
            }

            parkingCardOrderDto.setCarParkingSpaceId(carParkingSpaceDto.getId());
            Date deadline = parkingCardOrderService.approve(parkingCardOrderDto);
            if (Objects.isNull(deadline)) {
                return Response.error("审核异常");
            }
            parkingGateCmdBusiness.authorize(parkingCardOrderDto.getVillageId(), parkingCardOrderDto.getLicense()
                    , parkingCardOrderDto.getLicenseColor(), deadline, parkingCardOrderDto.getId());

        } else if (auditOrderReq.getStatus().equals(ParkingCardOrderConstants.CLOSE_TYPE)) {
            // 驳回，直接发起退款
            LoginUserSession sysUser = SessionHolder.getSysUser();
            Preconditions.checkNotNull(sysUser);

            Response<Object> refundResp = payBusiness.sendRefundRequest(parkingCardOrderDto.getOrderNo()
                    , parkingCardOrderDto.getOrderNo(), parkingCardOrderDto.getPayAmount(), OrderRefundConstants.RefundType.PERSON.getType(), sysUser.getAccount());
            if (!refundResp.isSuccess()) {
                return refundResp;
            }

            ParkingCardOrderDto newlyDto = new ParkingCardOrderDto();
            newlyDto.setId(parkingCardOrderDto.getId());
            newlyDto.setAuditStatus(ParkingCardOrderConstants.OrderAuditStatusEnum.IS_REJECT.getAuditStatus());
            parkingCardOrderService.updateById(newlyDto);
        }
        return Response.ok();
    }
}
